/********************************************
 * 功能说明: 
 * 模块名称: 
 * 系统名称: 
 * 软件版权: 北京银杉金服科技有限公司
 * 系统版本: 1.0.0
 * 开发人员: zhangfb
 * 开发时间: 2018/12/1 16:34
 * 审核人员: 
 * 相关文档: 
 * 修改记录: 修改日期 修改人员 修改说明
 *********************************************/
package com.hyacinth.util.future;

import java.util.Arrays;
import java.util.List;
import java.util.Random;
import java.util.concurrent.*;
import java.util.stream.Collectors;

/**
 * @author zhangfb
 * @version 1.0.0.1
 * @since JDK 1.8
 */
public class Shop {

    private static List<Shop> shops = Arrays.asList(
            new Shop("AA"), new Shop("BB"),
            new Shop("CC"), new Shop("DD"),
            new Shop("EE"), new Shop("FF"),
            new Shop("GG"), new Shop("HH"));

    private static final Executor executor = Executors.newFixedThreadPool(Math.min(shops.size(), 100), r -> {
        Thread thread = new Thread(r);
        thread.setDaemon(true);
        return thread;
    });

    private String shopName;

    public Shop(String shopName) {
        this.shopName = shopName;
    }

    public String getShopName() {
        return shopName;
    }

    //方法调用时间：2001
//    public static void main(String[] args) {
//        Shop shop = new Shop("BestShop");
//        long start = System.nanoTime();
//        double prise = shop.getPrise("clothes");
//        System.out.printf("Price is %.2f%n",price);
//        // do something
//        doSomeThing();
//        long invocationTime = (System.nanoTime() - start) / 1000000;
//        System.out.println("方法调用时间："+invocationTime);
//    }

//    public static void main(String[] args) {
//        Shop shop = new Shop("BestShop");
//        long start = System.nanoTime();
//        Future<Double> clothes = shop.getPriseAsync("clothes");
//        // do something
//        doSomeThing();
//        try {
//            Double price = clothes.get(1, TimeUnit.SECONDS);
//            System.out.printf("Price is %.2f%n",price);
//        } catch (Exception e) {
//            e.printStackTrace();
//        }
//        long invocationTime = (System.nanoTime() - start) / 1000000;
//        System.out.println("方法调用时间："+invocationTime);
//    }

    public static void main(String[] args) {
        System.out.println(Runtime.getRuntime().availableProcessors());
        long start = System.nanoTime();
        System.out.println(findPricesAsync("myPhone"));
        long invocationTime = (System.nanoTime() - start) / 1000000;
        System.out.println("方法调用时间："+invocationTime);
    }


    public static List<String> findPrices(String product) {
//        return shops.stream()
        return shops.stream() //并行流
                .map(shop -> String.format("%s price is %.2f", shop.getShopName(), shop.getPrise(product)))
                .collect(Collectors.toList());
    }

    public static List<String> findPricesAsync(String product) {
//        return shops.stream()
        List<CompletableFuture<String>> collect = shops.stream() //并行流
                .map(shop ->
                        CompletableFuture.supplyAsync(() -> String.format("%s price is %.2f", shop.getShopName(), shop.getPrise(product)), executor))
                .collect(Collectors.toList());
        return collect.stream()
                .map(CompletableFuture::join)
                .collect(Collectors.toList());
    }


    public static Future<Double> getPriseAsync(String product) {
//        CompletableFuture<Double> future = new CompletableFuture<>();
//        new Thread(() -> {
//            try {
//                double price = calculatePrice(product);
//                future.complete(price);
//            } catch (Exception ex) {
//                future.completeExceptionally(ex);
//            }
//        }).start();
//        return future;
        return CompletableFuture.supplyAsync(() -> calculatePrice(product));
    }

    public double getPrise(String product) {
        return calculatePrice(product);
    }

    private static double calculatePrice(String product) {
        delay();
        return new Random().nextDouble() * product.charAt(0) + product.charAt(1);
    }
//
//    public String getPrice(String product) {
//        double price = calculatePrice(product);
//        Discount.Code code = Discount.Code.values()[
//                random.nextInt(Discount.Code.values().length)];
//        return String.format("%s:%.2f:%s", name, price, code);
//    }

    /**
     * 延迟1s
     */
    public static void delay() {
        try {
            Thread.sleep(1000L);
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }
    }

    public static void doSomeThing(){
        delay();
    }

}
